#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include <ctype.h>
#include <stdlib.h>//TODO: 某些头文件
#define MAX_BUFFER 1024

void* thread_function(void* arg_array) {
    int nr_bytes_read, char_index;
    char receive_and_send_buffer[MAX_BUFFER];
    int* p_arg = (int*)arg_array;
    int thread_session_socket = *p_arg;
    printf("thread_session_socket = %d\n", thread_session_socket);
    while (1) {
        nr_bytes_read = read(thread_session_socket, receive_and_send_buffer, MAX_BUFFER);//TODO: 尝试从socket读取
        if (receive_and_send_buffer[0] == '#')//TODO: 如果错误，或没能从socket读取字符
            break;
        printf("Message from client(%d): %s\n", nr_bytes_read, receive_and_send_buffer);
        for (char_index = 0; char_index < nr_bytes_read; char_index++)
            receive_and_send_buffer[char_index] = toupper(receive_and_send_buffer[char_index]);//TODO: 转换为大写
        write(thread_session_socket, receive_and_send_buffer, char_index);//TODO: 返回给客户端
    }
    close(thread_session_socket);//TODO: 关闭socket
    return 0;
}

int main(int argc, char* argv[]) {
    socklen_t size_of_client_sockaddr;
    pthread_t tid;
    int listen_socket;
    int session_socket;
    int return_code;
    int port_number;

    struct sockaddr_in client_remote_sockaddr;
    struct sockaddr_in server_local_sockaddr;

    //服务器端运行时要给出端口信息，该端口为监听端口 
    if (argc != 2) {
        printf("Usage:%s port_number \n", argv[0]);
        return 1;
    }

    //获得输入的端口 
    port_number = atoi(argv[1]);

    //创建套接字用于服务器的监听 
    listen_socket = (PF_INET, SOCK_STREAM, 0);//TODO: socket()
    if (listen_socket < 0) {//TODO: 如果出错
        perror("ERR socket.");
        return 1;
    }

    //填充关于服务器的套节字信息
    memset(&server_local_sockaddr, 0, sizeof(server_local_sockaddr));
    server_local_sockaddr.sin_family = AF_INET;
    server_local_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_local_sockaddr.sin_port = htons(port_number);

    //将服务器和套节字绑定
    return_code = bind(listen_socket, (struct sockaddr *)&server_local_sockaddr, sizeof(server_local_sockaddr));//TODO: 调用bind绑定地址和端口（提供服务的位置）
    if (return_code == -1) {//TODO: 如果出错
        perror("ERR bind.");
        close(listen_socket);//TODO: 关闭监听socket
        return 1;
    }

    //监听指定端口，连接5个客户端 
    return_code = (listen_socket, 5);//TODO: 请求监听、提供服务
    if (return_code == -1) {//TODO: 如果出错
        perror("ERR listen.");
        close(listen_socket);//TODO: 关闭监听socket
        return 1;
    }

    //对每个连接来的客户端创建一个线程，单独与其进行通信。
    //首先调用read函数读取客户端发送来的信息，将其转换成大写后发送回客户端,#退出。
    while (1) {
        size_of_client_sockaddr = sizeof(client_remote_sockaddr);
        //TODO: 12345 改为自己的学号，此处不要修改write调用和STDOUT_FILENO参数！
        write(STDOUT_FILENO, "Listening & Accepting for 201930310050 ...\n", strlen("Listening & Accepting for 201930310050 ...\n"));
        return_code = accept(listen_socket, (struct sockaddr *)&client_remote_sockaddr, &size_of_client_sockaddr);//TODO: 调用accept阻塞，接到客户机时返回 session_socket
        if (return_code < 0) {//TODO: 如果出错
            if (errno == EINTR) continue;
            else {
                perror("ERR accept(): cannot accept client connect request");
                close(listen_socket);//TODO: 关闭socket
                return 1;
            }
        }
        printf("session_socket = %d\n", session_socket); //打印建立连接的客户端产生的套节字
        return_code = pthread_create(&tid, NULL, thread_function, &session_socket);//TODO: 调用 pthread_create，将 session_socket传递给 thread_function
        if (return_code == -1) {//TODO: 如果出错
            perror("ERR pthread_create()");
            close(listen_socket);//TODO: 关闭一个socket
            close(session_socket);//TODO: 关闭另一个socket
            return 1;
        }
    }
    return 0;
}
